package ahblue.cn.tanzi.view.video;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.pili.pldroid.player.AVOptions;
import com.pili.pldroid.player.PLOnAudioFrameListener;
import com.pili.pldroid.player.PLOnBufferingUpdateListener;
import com.pili.pldroid.player.PLOnCompletionListener;
import com.pili.pldroid.player.PLOnErrorListener;
import com.pili.pldroid.player.PLOnInfoListener;
import com.pili.pldroid.player.PLOnPreparedListener;
import com.pili.pldroid.player.PLOnSeekCompleteListener;
import com.pili.pldroid.player.PLOnVideoFrameListener;
import com.pili.pldroid.player.PLOnVideoSizeChangedListener;
import com.pili.pldroid.player.PlayerState;
import com.pili.pldroid.player.widget.PLVideoView;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import ahblue.cn.tanzi.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * 七牛播放器https://developer.qiniu.com/pili/sdk/1210/the-android-client-sdk
 */

public class MediaPlayer extends LinearLayout implements PLOnPreparedListener, PLOnInfoListener, PLOnCompletionListener,
        PLOnVideoSizeChangedListener, PLOnErrorListener, PLOnBufferingUpdateListener, PLOnSeekCompleteListener, PLOnVideoFrameListener, PLOnAudioFrameListener {
    @BindView(R.id.video)
    PLVideoView mVideoView;
    @BindView(R.id.tv_current_time)
    TextView tvCurrentTime;
    @BindView(R.id.tv_total_time)
    TextView tvTotalTime;
    @BindView(R.id.seekBar)
    SeekBar seekBar;
    @BindView(R.id.refresh)
    LinearLayout refresh;
    @BindView(R.id.llplay)
    RelativeLayout llplay;
    @BindView(R.id.startPlay)
    ImageView startPlay;
    @BindView(R.id.enlarge)
    ImageView enlarge;
    @BindView(R.id.llcontro)
    LinearLayout llcontro;

    private int mDisplayAspectRatio = PLVideoView.ASPECT_RATIO_FIT_PARENT; //default 播放器展示模式
    private int codec = 10;//超时时间
    private boolean islive = false;// true 直播  false 非直播
    private long totalTime;
    private View loadingView;
    private String videoPath = "";
    private long mLastPosition;
    private boolean isFullScreen = false;
    private boolean isPlaying = false;
    private ImageView coverView;
    private Activity mContext;

    public MediaPlayer(Context context) {
        this(context, null);
    }

    public MediaPlayer(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MediaPlayer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @OnClick({R.id.refresh, R.id.rootprv, R.id.enlarge,R.id.llplay})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.rootprv:
                showAndNo();
                break;
            case R.id.refresh:
                mVideoView.seekTo(mLastPosition);
                startPlay();
                break;
            case R.id.enlarge:
//                setVercitialFullScreen(true);
                break;
            case R.id.llplay:
                startPlay();
                break;
        }
    }

    // 显示隐藏相关按钮
    private void showAndNo() {
        if (llcontro.getVisibility() != VISIBLE) {
            llcontro.setVisibility(VISIBLE);
//            enlarge.setVisibility(VISIBLE);
            llplay.setVisibility(VISIBLE);
        } else {
            llcontro.setVisibility(GONE);
            enlarge.setVisibility(GONE);
            llplay.setVisibility(GONE);
        }
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        ButterKnife.bind(this);
        initPlayer();
    }

    private void initPlayer() {
        loadingView = findViewById(R.id.LoadingView);
        mVideoView.setBufferingIndicator(loadingView);
        //设置播放封面
        coverView = (ImageView) findViewById(R.id.CoverView);
        setCoverView(coverView);

        //播放参数配置
        AVOptions options = new AVOptions();
        // 解码方式:
//         codec=AVOptions.MEDIA_CODEC_HW_DECODE;//硬解
        codec = AVOptions.MEDIA_CODEC_SW_DECODE; //软解  解决后台切换视频,再次出现视频延迟五秒左右出现
//        codec = AVOptions.MEDIA_CODEC_AUTO;// 硬解优先，失败后自动切换到软解
        // 默认值是：MEDIA_CODEC_SW_DECODE
        options.setInteger(AVOptions.KEY_MEDIACODEC, codec);
        // 准备超时时间，包括创建资源、建立连接、请求码流等，单位是 ms
        // 默认值是：无
        options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
        // 默认的缓存大小，单位是 ms
        // 默认值是：500
        options.setInteger(AVOptions.KEY_CACHE_BUFFER_DURATION, 1000);
        // 最大的缓存大小，单位是 ms
        // 默认值是：2000
        options.setInteger(AVOptions.KEY_MAX_CACHE_BUFFER_DURATION, 3000);
        // 设置 DRM 密钥
        //        byte[] key = {xxx, xxx, xxx, xxx, xxx ……};
        //        options.setByteArray(AVOptions.KEY_DRM_KEY, key);
        // 设置本地缓存目录--》目前只支持 HTTP(s)-mp4 文件点播
        // 不缓存,一旦缓存没有权限就会崩溃ANR
        // 目前只支持 mp4 点播
        // 默认值是：无
//        options.setString(AVOptions.KEY_CACHE_DIR, Config.DEFAULT_CACHE_DIR);
        // 开启解码后的视频数据回调
        // 默认值是：0
        options.setInteger(AVOptions.KEY_VIDEO_DATA_CALLBACK, 1);
        // 开启解码后的音频数据回调
        // 默认值是：0
        options.setInteger(AVOptions.KEY_VIDEO_DATA_CALLBACK, 1);

        // 开启自定义视频数据渲染
        // 默认值是：0，由 SDK 内部渲染视频
        options.setInteger(AVOptions.KEY_VIDEO_RENDER_EXTERNAL, 0);
        // 开启自定义音频数据播放
        // 默认值是：0，由 SDK 内部播放音频
        options.setInteger(AVOptions.KEY_VIDEO_RENDER_EXTERNAL, 0);

        // DNS 解析优化
        //为了解决部分地区和某些网络条件下 DNS 解析过慢，导致播放首开时间过长的问题，从 1.3.0 版本开始，支持提前完成 DNS 解析

        //设置播放器展示模式
//        mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
        mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);

        //设置播放状态监听器
        mVideoView.setOnPreparedListener(this);
        mVideoView.setOnInfoListener(this);
        mVideoView.setOnCompletionListener(this);
        mVideoView.setOnVideoSizeChangedListener(this);
        mVideoView.setOnErrorListener(this);
        mVideoView.setOnBufferingUpdateListener(this);
        mVideoView.setOnSeekCompleteListener(this);
        mVideoView.setOnVideoFrameListener(this);
        mVideoView.setOnAudioFrameListener(this);
        setVolume(1.0f, 1.0f);

        // 请在开始播放之前配置
        mVideoView.setAVOptions(options);

        //设置播放地址
//        mVideoView.setVideoPath(videoPath);
//        mVideoView.setLooping(false);

        //MediaController，您可以随意修改满足定制化需求，将该控制器控件关联到 PLVideoView
//        MediaController mMediaController = new MediaController(getContext());
//        mMediaController.setOnClickSpeedAdjustListener(mOnClickSpeedAdjustListener);
        // sdk 自带的视频操作控制器
//        mVideoView.setMediaController(mMediaController);

        //进度条监听
        seekBar.setOnSeekBarChangeListener(onseekbarChangeListener);
    }

    private MediaController.OnClickSpeedAdjustListener mOnClickSpeedAdjustListener = new MediaController.OnClickSpeedAdjustListener() {
        @Override
        public void onClickNormal() {
            // 0x0001/0x0001 = 1
            mVideoView.setPlaySpeed(0X00010001);
        }

        @Override
        public void onClickFaster() {
            // 0x0002/0x0001 = 2
            mVideoView.setPlaySpeed(0X00020001);
        }

        @Override
        public void onClickSlower() {
            // 0x0001/0x0002 = 0.5
            mVideoView.setPlaySpeed(0X00010002);
        }
    };

    /**
     * 进度条
     */
    private SeekBar.OnSeekBarChangeListener onseekbarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (fromUser) {
                seelTo(progress);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    };

    /**
     * 拖动进度条，改变视频进度
     *
     * @param progress
     */
    public void seelTo(int progress) {
        if (totalTime != 0) {
            mVideoView.seekTo((long) (((float) progress / 1000) * totalTime));
        }
    }

    // 监听播放器的 prepare 过程，该过程主要包括：创建资源、建立连接、请求码流等等，当 prepare 完成后，SDK 会回调该对象的 onPrepared 接口，
    // 下一步则可以调用播放器的 start() 启动播放。
    @Override
    public void onPrepared(int i) {
        Log.d("videoview", "onPrepared: " + i);
        //当播放器准备就绪后，会回调该接口\
        //判断非直播下获取视屏时长和进度
        if (!islive && null != mVideoView) {
            totalTime = mVideoView.getDuration();
            progressHandle.sendEmptyMessageDelayed(0, 1000);
            tvTotalTime.setText(generateTime(totalTime) + "");
        }

    }

    /**
     * 视频播放进度
     */
    private Handler progressHandle = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (null != mVideoView) {
                if (mVideoView.getCurrentPosition() > totalTime)
                    tvCurrentTime.setText(generateTime(totalTime) + "");
                else
                    tvCurrentTime.setText(generateTime(mVideoView.getCurrentPosition()) + "");

                if (mVideoView.getCurrentPosition() <= totalTime) {
                    int current = (int) ((new Long(mVideoView.getCurrentPosition()).floatValue()) / (new Long(totalTime).floatValue()) * 1000);
                    seekBar.setProgress(current);
                }

                if (mVideoView.getCurrentPosition() <= totalTime) {
                    sendEmptyMessageDelayed(0, 1000 - (mVideoView.getCurrentPosition() % 1000));
                    updateStartPlay();
                }
            }
        }
    };

    /**
     * what 定义了消息类型，extra 是附加参数
     * what 	value 	描述
     * MEDIA_INFO_UNKNOWN 	1 	未知消息
     * MEDIA_INFO_VIDEO_RENDERING_START 	3 	第一帧视频已成功渲染
     * MEDIA_INFO_CONNECTED 	200 	连接成功
     * MEDIA_INFO_METADATA 	340 	读取到 metadata 信息
     * MEDIA_INFO_BUFFERING_START 	701 	开始缓冲
     * MEDIA_INFO_BUFFERING_END 	702 	停止缓冲
     * MEDIA_INFO_SWITCHING_SW_DECODE 	802 	硬解失败，自动切换软解
     * MEDIA_INFO_VIDEO_ROTATION_CHANGED 	10001 	获取到视频的播放角度
     * MEDIA_INFO_AUDIO_RENDERING_START 	10002 	第一帧音频已成功播放
     * MEDIA_INFO_VIDEO_GOP_TIME 	10003 	获取视频的I帧间隔
     * MEDIA_INFO_VIDEO_BITRATE 	20001 	视频的码率统计结果
     * MEDIA_INFO_VIDEO_FPS 	20002 	视频的帧率统计结果
     * MEDIA_INFO_AUDIO_BITRATE 	20003 	音频的帧率统计结果
     * MEDIA_INFO_AUDIO_FPS 	20004 	音频的帧率统计结果
     **/
    @Override
    public void onInfo(int what, int extra) {
//        Log.d("videoview", "onInfo: " + what + "  " + extra);
        refresh.setVisibility(View.GONE);
        switch (what) {
            case MediaPlayer.MEDIA_INFO_BUFFERING_START://开始缓冲
//                startAnimation();
                loadingView.setVisibility(View.VISIBLE);
                llplay.setVisibility(GONE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END://停止缓冲
                loadingView.setVisibility(View.GONE);
//                endAnimation();
                break;
        }
    }

    /**
     * 该回调用于监听当前播放的视频流的尺寸信息，在 SDK 解析出视频的尺寸信息后，会触发该回调，开发者可以在该回调中调整 UI 的视图尺寸。
     *
     * @param i
     * @param i1
     */
    @Override
    public void onVideoSizeChanged(int i, int i1) {
//        Log.d("videoview", "onVideoSizeChanged " + i + "  " + i1);
    }

    /**
     * 用于监听播放器的错误消息，一旦播放过程中产生任何错误信息,SDK 都会回调该接口，返回值决定了该错误是否已经被处理，如果返回 false，则代表没有被处理，
     * 下一步则会触发 onCompletion 消息
     * errorCode 	value 	描述
     * MEDIA_ERROR_UNKNOWN 	-1 	未知错误
     * ERROR_CODE_OPEN_FAILED 	-2 	播放器打开失败
     * ERROR_CODE_IO_ERROR 	-3 	网络异常
     * ERROR_CODE_SEEK_FAILED 	-4 	拖动失败
     * ERROR_CODE_HW_DECODE_FAILURE 	-2003 	硬解失败
     **/
    @Override
    public boolean onError(int errorCode) {
        Log.d("videoview", "onError " + errorCode);
        loadingView.setVisibility(GONE);
//        refresh.setVisibility(VISIBLE);
        //播放失败需要停止，记录最后一帧数据
        onClickStop();
        switch (errorCode) {
            case PLOnErrorListener.ERROR_CODE_IO_ERROR:
                /**
                 * SDK will do reconnecting automatically
                 */
                showToastTips("IO Error !");
                return false;
            case PLOnErrorListener.ERROR_CODE_OPEN_FAILED:
                showToastTips("failed to open player !");
                break;
            case PLOnErrorListener.ERROR_CODE_SEEK_FAILED:
                showToastTips("failed to seek !");
                break;
            default:
                showToastTips("unknown error !");
                break;
        }
        return true;
    }

    /**
     * Sets video path.
     *
     * @param path the path of the video.
     */
    public void setVideoPath(String path, Activity activity) {
        this.mContext = activity;
        this.videoPath = path;
        mVideoView.setVideoPath(path);
    }

    /**
     * Sets video path
     *
     * @param path    path of the video
     * @param headers http headers
     */
    public void setVideoPath(String path, Map<String, String> headers) {
        mVideoView.setVideoPath(path, headers);
    }

    /**
     * 该回调用于监听 seek 完成的消息，当调用的播放器的 seekTo 方法后，SDK 会在 seek 成功后触发该回调。
     */
    @Override
    public void onSeekComplete() {
        Log.d("onSeekComplete", "onSeekComplete: ");
    }

    /**
     * 获取视频数据回调的对象
     * 回调一帧视频帧数据
     *
     * @param data   视频帧数据
     * @param size   数据大小
     * @param width  视频帧的宽
     * @param height 视频帧的高
     * @param format 视频帧的格式，0 代表 I420，目前只支持 I420
     * @param ts     时间戳，单位是毫秒
     */
    @Override
    public void onVideoFrameAvailable(byte[] data, int size, int width, int height, int format, long ts) {

    }

    /**
     * 获取音频数据回调的对象
     * 回调一帧音频帧数据
     *
     * @param data       音频帧数据
     * @param size       数据大小
     * @param samplerate 采样率
     * @param channels   通道数
     * @param datawidth  位宽，目前默认转换为了16bit位宽
     * @param ts         时间戳，单位是毫秒
     */
    @Override
    public void onAudioFrameAvailable(byte[] data, int size, int samplerate, int channels, int datawidth, long ts) {
//        Log.e("MediaPlayer", "onAudioFrameAvailable: " + size + ", " + samplerate + ", " + channels + ", " + datawidth + ", " + ts);
    }

    /**
     * 开始播放
     */
    public void startPlay() {
        if (mVideoView != null) {
            if (getIsPlaying()) {
                pausePlay();
            } else {
                mVideoView.start();
                isPlaying = true;
                llplay.setVisibility(GONE);
            }
            updateStartPlay();
        }
    }

    /**
     * 暂停播放
     */
    public void pausePlay() {
        if (mVideoView != null) {
            if (mVideoView.isPlaying()) {
                onClickStop();
            }
        }
    }


    /**
     * 停止
     *
     * @param
     */
    private void onClickStop() {
        if (mVideoView != null) {
            mLastPosition = mVideoView.getCurrentPosition();
            mVideoView.pause();
            isPlaying = false;
            llplay.setVisibility(VISIBLE);
            updateStartPlay();
        }

    }

    /**
     * 调节音量
     *
     * @param leftVolume
     * @param rightVolume
     */
    public void setVolume(float leftVolume, float rightVolume) {
        mVideoView.setVolume(leftVolume, rightVolume);
//        setVolume(0.0f, 0.0f);//静音效果
    }

    /**
     * 在开始播放前，PLVideoView、PLVideoView 可以显示封面图片
     *
     * @param coverView
     */
    public void setCoverView(ImageView coverView) {
        mVideoView.setCoverView(coverView);
    }

    /**
     * 在播放过程中，用户可以调用接口，获取播放器当前状态
     *
     * @return
     */
    public PlayerState getPlayerState() {
        return mVideoView.getPlayerState();
    }

    /**
     * 在播放过程中，用户可以调用接口，获取当前播放流的 METADATA 信息
     *
     * @return
     */
    public HashMap<String, String> getMetadata() {
        return mVideoView.getMetadata();
    }

    /**
     * 获取实时统计信息
     */
    public int getVideoFps() {
        return mVideoView.getVideoFps();
    }

    public long getVideoBitrate() {
        return mVideoView.getVideoBitrate();
    }

    /**
     * 设置倍数播放
     *
     * @param speed 倍数值，16 进制表示，高 4 位代表分子，低 4 位代表分母
     *              例如：0X00010002 表示 0.5 倍数，0X00040001 表示 4 倍数
     *              范围：0.1～32 倍数
     */
    public void setPlaySpeeds(int speed) {
        mVideoView.setPlaySpeed(speed);
    }

    /**
     * //纵向半屏幕与横向全屏
     */
    private int mRotation = 0;

    public void onClickRotate() {
        mRotation = (mRotation + 90) % 180;
//        mVideoView.setDisplayOrientation(mRotation);    //PLVideoTextureView生效
        mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
        if (playerControllerListener != null)
            playerControllerListener.roatate(mRotation);
    }

    /**
     * 纵向全屏
     */
    public void setVercitialFullScreen(boolean b) {
        if (b) {
            mRotation = 1;
            isFullScreen = true;
        } else {
            mRotation = 2;
            isFullScreen = false;
        }
        mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
        if (playerControllerListener != null) {
            playerControllerListener.roatate(mRotation);
            playerControllerListener.setScreenFull(isFullScreen);
        }

    }

    // 设置
    public void onClickSwitchScreen() {
        mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
        mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
        switch (mVideoView.getDisplayAspectRatio()) {
            case PLVideoView.ASPECT_RATIO_ORIGIN:
                showToastTips("Origin mode");
                break;
            case PLVideoView.ASPECT_RATIO_FIT_PARENT:
                showToastTips("Fit parent !");
                break;
            case PLVideoView.ASPECT_RATIO_PAVED_PARENT:
                showToastTips("Paved parent !");
                break;
            case PLVideoView.ASPECT_RATIO_16_9:
                showToastTips("16 : 9 !");
                break;
            case PLVideoView.ASPECT_RATIO_4_3:
                showToastTips("4 : 3 !");
                break;
            default:
                break;
        }
    }

    private Toast mToast = null;

    private void showToastTips(final String tips) {
        mContext.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mToast != null) {
                    mToast.cancel();
                }
                mToast = Toast.makeText(mContext, tips, Toast.LENGTH_SHORT);
                mToast.show();
            }
        });
    }

    /**
     * 关于播放器相关的控制传达器
     */
    private playerController playerControllerListener;

    /**
     * 该对象用于监听播放结束的消息
     * 如果是播放文件，则是播放到文件结束后产生回调
     * 如果是在线视频，则会在读取到码流的EOF信息后产生回调，回调前会先播放完已缓冲的数据
     * 如果播放过程中产生onError，并且没有处理的话，最后也会回调本接口
     * 如果播放前设置了 setLooping(true)，则播放结束后会自动重新开始，不会回调本接口
     **/
    @Override
    public void onCompletion() {
        // 播放结束
        Log.d("videoview", "onCompletion ");
        onClickStop();
    }

    /**
     * 该回调用于监听当前播放器已经缓冲的数据量占整个视频时长的百分比，在播放直播流中无效，仅在播放文件和回放时才有效
     *
     * @param i
     */
    @Override
    public void onBufferingUpdate(int i) {

    }

    public void release() {
        if (mVideoView != null) {
//            mVideoView.pause();
            mVideoView.stopPlayback();
            mVideoView = null;
        }
//        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
//        audioManager.abandonAudioFocus(null);
    }


    public interface playerController {
        void roatate(int r);//播放器半屏与全屏切换

        void setScreenFull(boolean isFullScreen);//播放器状态（全屏，非全屏）

    }

    public void setPlayerControListener(playerController listener) {
        playerControllerListener = listener;
    }

    //开启动画
    private void startAnimation() {
        RotateAnimation an = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        an.setInterpolator(new LinearInterpolator());//不停顿
        an.setRepeatCount(-1);//重复次数
        an.setFillAfter(true);//停在最后
        an.setDuration(600);
        loadingView.startAnimation(an);
    }

    //关闭动画
    private void endAnimation() {
        loadingView.clearAnimation();
    }

    //获取播放器是否处于播放状态
    public boolean getIsPlaying() {
        return mVideoView.isPlaying();
    }

    //更新播放暂停按钮状态
    private void updateStartPlay() {
        if (isPlaying)
            startPlay.setImageResource(R.drawable.jz_pause_normal);
        else
            startPlay.setImageResource(R.drawable.jz_play_normal);
    }

    //将视屏时间转化string
    public static String generateTime(long position) {
        int totalSeconds = (int) (position / 1000);

        int seconds = totalSeconds % 60;
        int minutes = (totalSeconds / 60) % 60;
        int hours = totalSeconds / 3600;

        if (hours > 0) {
            return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
                    seconds).toString();
        } else {
            return String.format(Locale.US, "%02d:%02d", minutes, seconds)
                    .toString();
        }
    }
}
